from utils.sql_parser_util import RobustSQLTableParser
from utils.calendar_util import HolidayCalculator
from collections import defaultdict
import json, os
from typing import Dict, List, Any
import pandas as pd
from datetime import datetime, timedelta


def load_extra_data(extra_data_paths):
    """
    自动加载 xlsx / json / csv / txt 文件，
    所有结果统一转换为 list（集合）格式。
    返回: {filename: List[...]}
    """
    result = {}
    for path in extra_data_paths or []:
        if not os.path.exists(path):
            print(f"Warning: File not found - {path}")
            continue

        filename = os.path.basename(path)
        _, ext = os.path.splitext(filename)
        ext = ext.lower()

        try:
            if ext in (".xlsx", ".xls"):
                df = pd.read_excel(path, dtype=str)
                df = df.fillna("")
                result[filename] = df.to_dict(orient="records")  # 已是 list[dict]

            elif ext == ".csv":
                df = pd.read_csv(path, dtype=str)
                df = df.fillna("")
                result[filename] = df.to_dict(orient="records")  # 已是 list[dict]

            elif ext == ".json":
                with open(path, "r", encoding="utf-8") as f:
                    data = json.load(f)
                # 统一转为 list
                if isinstance(data, list):
                    result[filename] = data
                else:  # dict, str, int, etc.
                    result[filename] = [data]

            elif ext == ".txt":
                with open(path, "r", encoding="utf-8") as f:
                    content = f.read()
                # 方案1: 每行作为一个元素（适合记录）
                result[filename] = content.splitlines()
                # 方案2: 整体作为单个元素（适合模板/配置块）
                # result[filename] = [content]

            else:
                print(f"Unsupported file type: {filename}")
                result[filename] = []

        except Exception as e:
            print(f"Error loading {path}: {e}")
            result[filename] = []

    return result


def distribute_extra_datas(extra_datas, workdays, strategy="cycle"):
    """
    支持三种策略将外部数据分配到工作日：
      - "even": 均分（可能最后几天少，甚至空）
      - "cycle": 循环分配，先均分计算 如果数量少则循环
      - "full": 每天复制全部数据
    """
    if not workdays:
        return {}

    daily_extra = {day: {} for day in workdays}
    n_days = len(workdays)

    for filename, records in extra_datas.items():
        if not records:
            # 无数据：每天空列表
            for day in workdays:
                daily_extra[day][filename] = []
            continue

        if strategy == "even":
            # 均分：使用 chunk_list（允许空）
            chunks = chunk_list(records, n_days)
            for i, day in enumerate(workdays):
                daily_extra[day][filename] = chunks[i] if i < len(chunks) else []

        elif strategy == "cycle":
            if not records:
                # 无数据：每天空列表
                for day in workdays:
                    daily_extra[day][filename] = []
            else:
                n_days = len(workdays)
                n_records = len(records)

                if n_records >= n_days:
                    # ▼ 情况1：数据充足 → balanced 分配（前余数天多1条）
                    k, r = divmod(n_records, n_days)  # k=基础条数，r=需多分1条的天数
                    for i, day in enumerate(workdays):
                        start = i * k + min(i, r)
                        end = (i + 1) * k + min(i + 1, r)
                        daily_extra[day][filename] = records[start:end]
                else:
                    # ▼ 情况2：数据不足 → 循环分配，每天1条（不空）
                    for i, day in enumerate(workdays):
                        idx = i % n_records
                        daily_extra[day][filename] = [records[idx]]
        elif strategy == "full":
            # 每天全部
            for day in workdays:
                daily_extra[day][filename] = records.copy()  # 避免引用问题

        else:
            raise ValueError(f"Unsupported strategy: {strategy}")

    return daily_extra


def chunk_list(lst, n):
    """均分列表为 n 份，允许最后几份少或空"""
    if n <= 0:
        return []
    k, m = divmod(len(lst), n)
    return [lst[i * k + min(i, m) : (i + 1) * k + min(i + 1, m)] for i in range(n)]


def generate_adaptive_time_points(day_num: int, target_date: str):
    """
    自适应时间点生成策略，基于指定日期：

    - 若 day_num <= 16（均分间隔 ≥1小时）→ 使用 1 小时作为区间 迭代计算出对应day_num的节点
    - 若 day_num > 16（均分间隔 <1小时）→ 在 08:00:00 ~ 23:59:59 均匀分布 day_num 个点

    Args:
        day_num (int): 期望的时间点数量
        target_date (str): 日期字符串，格式 "YYYY-MM-dd"

    Returns:
        List[str]: 时间点列表，格式 ["YYYY-MM-dd HH:mm:ss", ...]
    """
    if day_num <= 0:
        day_num = 1

    # 解析指定日期
    try:
        base_date = datetime.strptime(target_date, "%Y-%m-%d").date()
    except ValueError as e:
        raise ValueError(
            f"Invalid date format: {target_date}. Expected YYYY-MM-dd"
        ) from e

    # 构造当天的起止时间：08:00:00 到 23:59:59
    start = datetime.combine(
        base_date, datetime.strptime("08:00:00", "%H:%M:%S").time()
    )
    end = datetime.combine(base_date, datetime.strptime("23:59:59", "%H:%M:%S").time())

    # 阈值：16 个点 ≈ 每小时一个（8~23 共 16 小时）
    if day_num <= 16:
        # 固定生成 16 个整点：08:00, 09:00, ..., 23:00
        points = []
        for hour in range(8, 8 + day_num):  # 8 到 23（含）
            dt = datetime.combine(base_date, datetime.min.time().replace(hour=hour))
            points.append(dt.strftime("%Y-%m-%d %H:%M:%S"))
        return points
    else:
        # 按 day_num 均匀分布（允许密集）
        total_seconds = int((end - start).total_seconds())  # 57599 秒
        points = []
        for i in range(day_num):
            if day_num == 1:
                dt = start
            else:
                offset = int(i * total_seconds / (day_num - 1))
                dt = start + timedelta(seconds=offset)
                if dt > end:
                    dt = end
            points.append(dt.strftime("%Y-%m-%d %H:%M:%S"))
        return points


def calculate_day(time_range: List[str], day_num: int) -> List[str]:
    result = []
    today_str = datetime.now().strftime("%Y-%m-%d")  # 用于失败或者未配置时
    if time_range and len(time_range) > 1:
        try:
            calculator = HolidayCalculator()
            calculator.preload_calendar_data(time_range[0], time_range[1])
            # 获取工作日
            workdays = calculator.get_workdays(time_range[0], time_range[1])
            for day in workdays:
                result.extend(generate_adaptive_time_points(day_num, day))
        except:

            result = generate_adaptive_time_points(day_num, today_str)
    else:
        result = generate_adaptive_time_points(day_num, today_str)

    return result


def convert(
    tables: List,
    relations: List,
    field_rule: Dict[str, Dict[str, str]],
    templates: Dict[str, Any] = {},
    extra_datas: List = [],
    distribution_strategy: str = "cycle",
    time_range: List = [],
    day_num: int = 1,
) -> str:
    """
    解析表结构转换为特定结构的JSON内容
    """
    result = {}
    parser = RobustSQLTableParser()
    table_result = []

    for table in tables:
        table_item = parser.parse_sql(table)
        struts = table_item["struts"]
        name = table_item["name"]
        field_rule_item = {} if name not in field_rule.keys() else field_rule[name]
        for field in field_rule_item.keys():
            for item in struts:
                if item["field"] == field:
                    item["rule"] = field_rule_item[field]

        table_result.append(table_item)

    groups = defaultdict(list)

    for left, right in relations:
        from_table, left_field = left.split(".", 1)
        to_table, right_field = right.split(".", 1)
        groups[(from_table, to_table)].append(
            {"left_field": left_field, "right_field": right_field}
        )

    # Convert to list of dicts
    relation_result = [
        {"from": from_table, "to": to_table, "on": fields}
        for (from_table, to_table), fields in groups.items()
    ]

    # 获取所有的工作日
    result["time_range"] = calculate_day(time_range, day_num)

    # 获取外部存储数据
    if extra_datas and len(extra_datas) > 0:
        extra_datas = load_extra_data(extra_datas)
        if len(result["time_range"]) > 0:
            daily_extra = distribute_extra_datas(
                extra_datas, result["time_range"], distribution_strategy
            )
            result["extra_datas"] = daily_extra
        else:
            result["extra_datas"] = extra_datas

    result["tables"] = table_result
    result["relations"] = relation_result
    result["templates"] = templates

    return json.dumps(result, ensure_ascii=False, indent=2)


def generate_mock_template(
    module_name,
    tables: List,
    relations: List,
    field_rule: Dict[str, Dict[str, str]],
    templates: Dict[str, Any] = {},
    extra_datas: List = [],
    distribution_strategy: str = "cycle",
    time_range: List = [],
    day_num: int = 1,
):
    """
    - distribution_strategy
    "even"（均分填充）将数据尽可能平均分到每天（如 5 条分给 3 天 →[2,2,1]），不足不补
    "cycle"（循环迭代）数据不够时循环使用，确保每天至少有1 条（如 2 条分 5 天 →[A,B,A,B,A]）
    "full"（全部复制）每天使用全部数据（如 2 条 → 每天都是[A,B]）
    """
    file_name = f"config/{module_name}.json"
    # 写入文件
    os.makedirs(os.path.dirname(file_name), exist_ok=True)
    with open(file_name, "w", encoding="utf-8") as f:
        f.write(
            convert(
                tables,
                relations,
                field_rule,
                templates,
                extra_datas,
                distribution_strategy,
                time_range,
                day_num,
            )
        )  # str 写入文本文件
    return os.path.abspath(file_name)


__all__ = ["generate_mock_template", "load_extra_data", "calculate_day"]
